/* Developed by Vinh, Nguyen Hong <mansofta@gmail.com>
 * Copyright HIENDAI SOFTWARE COMPANY 2004
 * http://www.hiendai.com.vn
 * contact@hiendai.com.vn
*/
using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Collections;
using System.Text.RegularExpressions;

namespace MarcXmlParser {

	public class CDatafields
	{	
	    protected	XmlNode ptCurrentRootNode;		
	    protected	XmlNodeList ptCurrentDatafieldList;
	    protected	static String UpperChars="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	    protected	static String LowerChars="abcdefghijklmnopqrstuvwxyz";
	
	private void make_TranslationString()
		{
			//Build conversion character string
//			UpperChars=
//			LowerChars=			
			//==========Special Upper Chars
			short[] VietUpperChars=new short[62]{192,193,7842,195,7840,258,7856,7854,7858,7860,
				7862,194,7846,7844,7848,7850,7852,272,200,201,
				7866,7868,7864,202,7872,7870,7874,7876,7878,204,
				205,7880,296,7882,210,211,7886,213,7884,212,
				7890,7888,7892,7894,7896,416,7900,7898,7902,7904,
				7906,217,218,7910,360,7908,431,7914,7912,7916,
				7918,7920};
			//==========Special Lowers Chars
			short[] VietLowerChars=new short[62]{224,225,7843,227,7841,259,7857,7855,7859,7861,
				7863,226,7847,7845,7849,7851,7853,273,232,233,
				7867,7869,7865,234,7873,7871,7875,7877,7879,236,
				237,7881,297,7883,242,243,7887,245,7885,244,
				7891,7889,7893,7895,7897,417,7901,7899,7903,7905,
				7907,249,250,7911,361,7909,432,7915,7913,7917,
				7919,7921};
			StringBuilder Lsb=new StringBuilder(LowerChars);
			StringBuilder Usb=new StringBuilder(UpperChars);
			Char myChar=' ';
			for(int i=0;i<62;i++) //Add Vietnamese characters to string
			{
				myChar=(Char)VietLowerChars[i];
				Lsb.Append(myChar);
				myChar=(Char)VietUpperChars[i];
				Usb.Append(myChar);
			}
			UpperChars=Usb.ToString();
			LowerChars=Lsb.ToString();
			//End build conversion character string	
		}
		
	public CDatafields(ref XmlNode ptRecordRootNode)
		{
			ptCurrentRootNode=ptRecordRootNode;
			ptCurrentDatafieldList=ptCurrentRootNode.SelectNodes("./*[local-name() ='datafield']");  
		}
	public void Refresh()
		{
			ptCurrentDatafieldList=ptCurrentRootNode.SelectNodes("./*[local-name() ='datafield']");  
		}
        public int Count
	{
		get
		{
			//ptCurrentDatafieldList=ptCurrentRootNode.SelectNodes("./*[local-name() ='datafield']");  
			return ptCurrentDatafieldList.Count; 
		}
	}
        public void Add(CDatafield ptDatafield)
		{	
			ptCurrentRootNode.AppendChild(ptCurrentRootNode.OwnerDocument.ImportNode(ptDatafield.RootNode,true));			  
		}
        public void Remove(int DatafieldIndex)
		{		
			ptCurrentRootNode.RemoveChild(ptCurrentDatafieldList.Item(DatafieldIndex));
		}
        public void Remove(ref CDatafield ptDatafield)
		{		
			ptCurrentRootNode.RemoveChild(ptDatafield.RootNode);
		}
        public void Clean()
		{					
			CDatafield ptDatafield;
			ptDatafield=new CDatafield();			
			for(int i=0;i<ptCurrentDatafieldList.Count;i++)
			{
                XmlNode myNode=ptCurrentDatafieldList.Item(i);
				ptDatafield.load_RootNode(ref myNode); 
				ptDatafield.Subfields.Clean();
				if(ptDatafield.Subfields.Count==0) //No Subfield in this Datafield
				{
					ptCurrentRootNode.RemoveChild(ptCurrentDatafieldList.Item(i));
				}
			}
			ptCurrentDatafieldList=ptCurrentRootNode.SelectNodes("./*[local-name() ='datafield']");  
		}

        public void Clean(String strAliveTags)
		{					
			CDatafield ptDatafield;
			ptDatafield=new CDatafield();			
			for(int i=0;i<ptCurrentDatafieldList.Count;i++)
			{
                XmlNode myNode = ptCurrentDatafieldList.Item(i);
				ptDatafield.load_RootNode(ref myNode); 
				if(strAliveTags.IndexOf(ptDatafield.Tag)<0)//this datafield is not being alive tags
				{ //kill this datafields
					ptCurrentRootNode.RemoveChild(ptCurrentDatafieldList.Item(i));	
				}
			}
			ptCurrentDatafieldList=ptCurrentRootNode.SelectNodes("./*[local-name() ='datafield']");  
		}
        public void Filter(String sTag)
		{
	  	    StringBuilder QueryStr = new StringBuilder();
			QueryStr.Append("./*[local-name() ='datafield'][@tag='");		
			QueryStr.Append(sTag);
			QueryStr.Append("']");
			ptCurrentDatafieldList=ptCurrentRootNode.SelectNodes(QueryStr.ToString());  
		}
        public void Filter(String sTag, String sCode, String sValue, bool bEqual)
		{
			//make translation strings
			if(UpperChars.Length==26||LowerChars.Length==26)
			{
				make_TranslationString();
			}
			StringBuilder QueryStr = new StringBuilder();
			QueryStr.Append("(./*[local-name() ='datafield'])[@tag='");		
			QueryStr.Append(sTag);
			QueryStr.Append("' and (./*[local-name() ='subfield'])[@code='");
			QueryStr.Append(sCode);
			if(bEqual)
			{
				QueryStr.Append("' and (translate(text() ,'"); QueryStr.Append(UpperChars); QueryStr.Append("','"); QueryStr.Append(LowerChars); QueryStr.Append("')=translate(");
				QueryStr.Append(XPathQuoteString(sValue));
				QueryStr.Append(",'"); QueryStr.Append(UpperChars); QueryStr.Append("','"); QueryStr.Append(LowerChars); QueryStr.Append("'))]]");
			} else
			{
				QueryStr.Append("' and contains(translate(.,'"); QueryStr.Append(UpperChars); QueryStr.Append("','"); QueryStr.Append(LowerChars); QueryStr.Append("'),translate(");
				QueryStr.Append(XPathQuoteString(sValue));
				QueryStr.Append(",'"); QueryStr.Append(UpperChars); QueryStr.Append("','"); QueryStr.Append(LowerChars); QueryStr.Append("'))]]");
			}
			ptCurrentDatafieldList=ptCurrentRootNode.SelectNodes(QueryStr.ToString());  
		}
        public void Filter(String sTag, String sCode1, String sValue1, String sCode2, String sValue2, bool bEqual)
		{
			//make translation strings
			if(UpperChars.Length==26||LowerChars.Length==26)
			{
				make_TranslationString();
			}
			StringBuilder QueryStr = new StringBuilder();
			QueryStr.Append("(./*[local-name() ='datafield'])[@tag='");		
			QueryStr.Append(sTag);
			if(bEqual)
			{
				QueryStr.Append("' and (./*[local-name() ='subfield'])[@code='");
				QueryStr.Append(sCode1);
				QueryStr.Append("' and translate(text(),'"); QueryStr.Append(UpperChars); QueryStr.Append("','"); QueryStr.Append(LowerChars); QueryStr.Append("')=translate(");
				QueryStr.Append(XPathQuoteString(sValue1));
				QueryStr.Append(",'"); QueryStr.Append(UpperChars); QueryStr.Append("','"); QueryStr.Append(LowerChars); QueryStr.Append("')] and (./*[local-name() ='subfield'])[@code='");
				QueryStr.Append(sCode2);
				QueryStr.Append("' and translate(text(),'"); QueryStr.Append(UpperChars); QueryStr.Append("','"); QueryStr.Append(LowerChars); QueryStr.Append("')=translate(");
				QueryStr.Append(XPathQuoteString(sValue2));			
				QueryStr.Append(",'"); QueryStr.Append(UpperChars); QueryStr.Append("','"); QueryStr.Append(LowerChars); QueryStr.Append("')]]");
			} else
			{
				QueryStr.Append("' and (./*[local-name() ='subfield'])[@code='");
				QueryStr.Append(sCode1);
				QueryStr.Append("' and contains(translate(.,'"); QueryStr.Append(UpperChars); QueryStr.Append("','"); QueryStr.Append(LowerChars); QueryStr.Append("'),translate(");
				QueryStr.Append(XPathQuoteString(sValue1));
				QueryStr.Append(",'"); QueryStr.Append(UpperChars); QueryStr.Append("','"); QueryStr.Append(LowerChars); QueryStr.Append("'))] and (./*[local-name() ='subfield'])[@code='");
				QueryStr.Append(sCode2);
				QueryStr.Append("' and contains(translate(.,'"); QueryStr.Append(UpperChars); QueryStr.Append("','"); QueryStr.Append(LowerChars); QueryStr.Append("'),translate(");
				QueryStr.Append(XPathQuoteString(sValue2));			
				QueryStr.Append(",'"); QueryStr.Append(UpperChars); QueryStr.Append("','"); QueryStr.Append(LowerChars); QueryStr.Append("'))]]");
			}
			ptCurrentDatafieldList=ptCurrentRootNode.SelectNodes(QueryStr.ToString());  
		}

        public void Filter(String sTag, String sCode1, String sValue1, String sCode2, String sValue2, String sCode3, String sValue3, bool bEqual)
		{
			//make translation strings
			if(UpperChars.Length==26||LowerChars.Length==26)
			{
				make_TranslationString();
			}

			StringBuilder QueryStr = new StringBuilder();
			QueryStr.Append("(./*[local-name() ='datafield'])[@tag='");		
			QueryStr.Append(sTag);
			if(bEqual)
			{
				QueryStr.Append("' and (./*[local-name() ='subfield'])[@code='");
				QueryStr.Append(sCode1);
				QueryStr.Append("' and translate(text(),'"); QueryStr.Append(UpperChars); QueryStr.Append("','"); QueryStr.Append(LowerChars); QueryStr.Append("')=translate(");
				QueryStr.Append(XPathQuoteString(sValue1));
				QueryStr.Append(",'"); QueryStr.Append(UpperChars); QueryStr.Append("','"); QueryStr.Append(LowerChars); QueryStr.Append("')] and (./*[local-name() ='subfield'])[@code='");
				QueryStr.Append(sCode2);
				QueryStr.Append("' and translate(text(),'"); QueryStr.Append(UpperChars); QueryStr.Append("','"); QueryStr.Append(LowerChars); QueryStr.Append("')=translate(");
				QueryStr.Append(XPathQuoteString(sValue2));			
				QueryStr.Append(",'"); QueryStr.Append(UpperChars); QueryStr.Append("','"); QueryStr.Append(LowerChars); QueryStr.Append("')] and (./*[local-name() ='subfield'])[@code='");
				QueryStr.Append(sCode3);
				QueryStr.Append("' and translate(text(),'"); QueryStr.Append(UpperChars); QueryStr.Append("','"); QueryStr.Append(LowerChars); QueryStr.Append("')=translate(");
				QueryStr.Append(XPathQuoteString(sValue3));			
				QueryStr.Append(",'"); QueryStr.Append(UpperChars); QueryStr.Append("','"); QueryStr.Append(LowerChars); QueryStr.Append("')]]");
			} else
			{
				QueryStr.Append("' and (./*[local-name() ='subfield'])[@code='");
				QueryStr.Append(sCode1);
				QueryStr.Append("' and contains(translate(.,'"); QueryStr.Append(UpperChars); QueryStr.Append("','"); QueryStr.Append(LowerChars); QueryStr.Append("'),translate(");
				QueryStr.Append(XPathQuoteString(sValue1));
				QueryStr.Append(",'"); QueryStr.Append(UpperChars); QueryStr.Append("','"); QueryStr.Append(LowerChars); QueryStr.Append("'))] and (./*[local-name() ='subfield'])[@code='");
				QueryStr.Append(sCode2);
				QueryStr.Append("' and contains(translate(.,'"); QueryStr.Append(UpperChars); QueryStr.Append("','"); QueryStr.Append(LowerChars); QueryStr.Append("'),translate(");
				QueryStr.Append(XPathQuoteString(sValue2));			
				QueryStr.Append(",'"); QueryStr.Append(UpperChars); QueryStr.Append("','"); QueryStr.Append(LowerChars); QueryStr.Append("'))] and (./*[local-name() ='subfield'])[@code='");
				QueryStr.Append(sCode3);
				QueryStr.Append("' and contains(translate(.,'"); QueryStr.Append(UpperChars); QueryStr.Append("','"); QueryStr.Append(LowerChars); QueryStr.Append("'),translate(");
				QueryStr.Append(XPathQuoteString(sValue3));			
				QueryStr.Append(",'"); QueryStr.Append(UpperChars); QueryStr.Append("','"); QueryStr.Append(LowerChars); QueryStr.Append("'))]]");
			}
			ptCurrentDatafieldList=ptCurrentRootNode.SelectNodes(QueryStr.ToString());  
		}

        public bool get_Datafield(String sTag, ref CDatafield ptDatafield)
		{
	  	    XmlNode ptXnode;
			StringBuilder QueryStr = new StringBuilder();
			QueryStr.Append("./*[local-name() ='datafield'][@tag='");		
			QueryStr.Append(sTag);
			QueryStr.Append("']");
			ptXnode=ptCurrentRootNode.SelectSingleNode(QueryStr.ToString());  		
			if(ptXnode!=null)
			{
				ptDatafield.load_RootNode(ref ptXnode); 
				return true;
			}else
			{
				return false;
			}
		}
        public CDatafield Datafield(int Index)
		{
			CDatafield ptDatafield;
			ptDatafield=new CDatafield();			
            XmlNode myNode=ptCurrentDatafieldList.Item(Index);
			ptDatafield.load_RootNode(ref myNode); 
			return ptDatafield;				
		}

        public CDatafield Datafield(String sTag)
		{
			CDatafield ptDatafield;
			ptDatafield=new CDatafield();					
	  	    XmlNode ptXnode;
			StringBuilder QueryStr = new StringBuilder();
			QueryStr.Append("./*[local-name() ='datafield'][@tag='");		
			QueryStr.Append(sTag);
			QueryStr.Append("']");
			ptXnode=ptCurrentRootNode.SelectSingleNode(QueryStr.ToString());
            if (ptXnode != null)
			{
				ptDatafield.load_RootNode(ref ptXnode); 
			}
			return ptDatafield;				
		}

		//03-01-2007
		//Solve single quote and double qoute
        public String XPathQuoteString(String inputstr)
		{
			StringBuilder outputstr=new StringBuilder();
			int q1=inputstr.IndexOf("\'");
			int q2=inputstr.IndexOf("\"");
			if((q1<0) && (q2<0))//no quotation marks
			{
				outputstr.Append("\'");
				outputstr.Append(inputstr);
				outputstr.Append("\'");			
			}else if((q1>=0) && (q2<0)) //only single quote
			{
					Regex regex = new Regex("\'");
					String[] tokens = regex.Split(inputstr);
					outputstr.Append("concat(");
					outputstr.Append("\'");
					outputstr.Append(tokens[0]); 
					outputstr.Append("\'");
					for (int i=1; i<tokens.Length; i++)
					{
						outputstr.Append(",");
						outputstr.Append("\"\'\"");
						outputstr.Append(",");
						outputstr.Append("\'");
						outputstr.Append(tokens[i]); 
						outputstr.Append("\'");
					}
					outputstr.Append(")");
			}else if((q1<0) && (q2>=0))
			{
					Regex regex = new Regex("\"");
					String[] tokens = regex.Split(inputstr);
					outputstr.Append("concat(");
					outputstr.Append("\'");
					outputstr.Append(tokens[0]); 
					outputstr.Append("\'");
					for (int i=1; i<tokens.Length; i++)
					{
						outputstr.Append(",");
						outputstr.Append("\'\"\'");
						outputstr.Append(",");
						outputstr.Append("\'");
						outputstr.Append(tokens[i]); 
						outputstr.Append("\'");
					}
					outputstr.Append(")");				
			}else if((q1>=0) && (q2>=0))
			{
				//solve single quote first and double quote inside
					Regex regex = new Regex("\'");
					String[] tokens = regex.Split(inputstr);
					outputstr.Append("concat(");
					//outputstr.Append("\'");
					outputstr.Append(SolveDoubleQoute(tokens[0])); 
					//outputstr.Append("\'");
					for (int i=1; i<tokens.Length; i++)
					{
						outputstr.Append(",");
						outputstr.Append("\"\'\"");
						outputstr.Append(",");
						//outputstr.Append("\'");
						outputstr.Append(SolveDoubleQoute(tokens[i])); 
						//outputstr.Append("\'");
					}
					outputstr.Append(")");				
			}
			return outputstr.ToString();
		}
		//inside concat of single quote add double quotes	
        public static String SolveDoubleQoute(String dbquotesstr)
		{
			StringBuilder outputstr=new StringBuilder();
			Regex regex = new Regex("\"");
			String[] tokens = regex.Split(dbquotesstr);
			if(tokens.Length==1)
			{
				outputstr.Append("\'");
				outputstr.Append(dbquotesstr);
				outputstr.Append("\'");
			}else
			{
				outputstr.Append("\'");
				outputstr.Append(tokens[0]); 
				outputstr.Append("\'");
				for (int i=1; i<tokens.Length; i++)
				{
					outputstr.Append(",");
					outputstr.Append("\'\"\'");
					outputstr.Append(",");
					outputstr.Append("\'");
					outputstr.Append(tokens[i]); 
					outputstr.Append("\'");
				}
			}
			return outputstr.ToString();
		}


	};
}
